import requests
from PIL import Image
import os
import time
from io import StringIO,BytesIO

def getTile(layer='img', projection='w', zoom='1', x='0', y='0', tk=''):
    '''获取天地图瓦片
    layer 图层
    '''
    src = 'http://t{}.tianditu.gov.cn/{}_{}/wmts?service=wmts&request=gettile&VERSION=1.0.0&LAYER={}&STYLE=default&TILEMATRIXSET={}&FORMAT=tiles&TILEMATRIX={}&TILEROW={}&TILECOL={}&tk={}'
    for source in range(8):
        try:
            headers = {
            'Host': "t{}.tianditu.gov.cn".format(source),
            'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47",
            'Cookie': "HWWAFSESID=44a6d8b1b8eb7d6335; HWWAFSESTIME=1660715969030; TDTSESID=rBACBGL8g8RStC+/gJUJAg==",
            'Referer': 'https://www.tianditu.gov.cn/'}
            src = src.format(source, layer, projection, layer, projection, zoom, x, y, tk)
            response = requests.get(src, headers=headers)
            img = Image.open(BytesIO(response.content)).convert('RGBA')
            return img
        except:
            print('trying t{}...'.format(source))
            continue

def get_tile(zoom, x, y, tk, filename=''):
    for i in range(10):
        try:
            base_img = Image.open(BytesIO(getTile('img', 'c', zoom, x, y, tk)))  # 底图
            over_img = Image.open(BytesIO(getTile('cia', 'c', zoom, x, y, tk))).convert('RGBA')  # 标记
        except:
            global source
            source = (source+1)%8
            print('trying t{}...'.format(source))
            continue
        else:
            break
    base_img.paste(over_img, (0, 0), mask=over_img)  # 叠加
    if filename:
        base_img.save("result5.png")
    return base_img     

def longitude2y(lg,zoom):
    '''经度转换为瓦片纵坐标'''
    return int((lg+180)/(360/(2**zoom)))

def latitude2x(la, zoom):
     '''纬度转换为瓦片横坐标'''
     return int((90-la)/(180/(2**(zoom-1))))

def getTiles1(zoom, start, end, tk):
    start_x, start_y = latitude2x(start[1],zoom), longitude2y(start[0],zoom)
    end_x, end_y = latitude2x(end[1],zoom), longitude2y(end[0],zoom)
    print('瓦片范围：（{}，{}）-（{}，{}）'.format(start_x,start_y, end_x, end_y))
    width = end_x - start_x + 1
    height = end_y - start_y + 1
    print('瓦片数量：{}*{}={}'.format(width,height,width*height))
    for x in range(start_x, end_x+1):
         for y in range(start_y, end_y+1):
            filename = '{:>02}-{:>08}-{:>08}.png'.format(zoom,x,y)
            if os.path.exists('images//'+filename):
                print('{} already exists'.format(filename))
            else:
                im = get_img(zoom, x, y, tk)
                im.save('images//'+filename)
                print('{} download succeed'.format(filename))

def get_area(zoom, start, end, tk):
    start_x, start_y = latitude2x(start[1],zoom), longitude2y(start[0],zoom)
    end_x, end_y = latitude2x(end[1],zoom), longitude2y(end[0],zoom)
    print('瓦片范围：（{}，{}）-（{}，{}）'.format(start_x,start_y, end_x, end_y))
    width = end_x - start_x + 1
    height = end_y - start_y + 1
    print('瓦片数量：{}*{}={}'.format(width,height,width*height))
    # 建立图层
    bg = Image.new('RGB', (256*height, 256*width), (255, 255, 255))
    for x in range(start_x, end_x+1):
         for y in range(start_y, end_y+1):
            im = get_img(zoom, x, y, tk)
            time.sleep(0.25)
            bg.paste(im,(256*(y-start_y), 256*(x-start_x))) #粘贴
            print((y-start_y, x-start_x), (height,width))
    bg.save('perfect.png')

def combineTiles(zoom, start_x, start_y, end_x, end_y):
    width = end_x - start_x + 1
    height = end_y - start_y + 1
    print('瓦片数量：{}*{}={}'.format(width,height,width*height))
    # 建立图层
    bg = Image.new('RGB', (256*height, 256*width), (255, 255, 255))
    for x in range(start_x, end_x+1):
         for y in range(start_y, end_y+1):
            filename = '{:>02}-{:>08}-{:>08}.png'.format(zoom,x,y)
            im = Image.open('images//'+filename)
            bg.paste(im,(256*(y-start_y), 256*(x-start_x))) #粘贴
    bg.save('perfect.png')

def getTiles(tk, area, zoom, layer, projection='w'):
    '''按要求获取图片，并存在文件夹里'''
    # 计算瓦片范围
    start_x, start_y = latitude2x(area[0],zoom), longitude2y(area[1],zoom)
    end_x, end_y = latitude2x(area[2],zoom), longitude2y(area[3],zoom)
    width = end_x - start_x + 1
    height = end_y - start_y + 1
    print('瓦片范围：（{}，{}）-（{}，{}）'.format(start_x,start_y, end_x, end_y))
    print('瓦片数量：{}*{}={}'.format(width,height,width*height))
    # 获取瓦片
    for x in range(start_x, end_x+1):
         for y in range(start_y, end_y+1):
            filename = '{:>02}-{:>08}-{:>08}.png'.format(zoom,x,y)
            if os.path.exists('images//'+filename):
                print('{} already exists'.format(filename))
            else:
                im = getTile(layer, 'w', zoom, x, y, tk=tk)
                im.save('images//'+filename)
                print('{} download succeed'.format(filename))

def get_map(tk, area, zoom, base_img, over_img, tile_cache, file_name):
    '''图片分为两层，底图、标记
    希望实现的功能是，输入密钥、经纬度范围、图像级别、底图、标记、是否保存缓存，生成一个图片
    - tk:密钥，是一个字符串列表或者单个字符串，当一个失败时，会循环进行其他的。
    - area:经纬度范围，是一个元组，包含4个数字，默认是(116.91, 36.78, 117.23, 36.58)济南的范围
    - zoom:图像级别，一个数字，1-18，默认12
    - base_img:底图类型，默认卫星图
    - over_img:标记类型，默认地名标记
    - tile_cache:瓦片缓存，布尔值，默认不缓存
    - file_name:保存文件的名称，默认为当前时间
    '''
    # 获取底图所有瓦片
    getTiles(tk, area=area, zoom=zoom, layer=base_img)
    # combineTiles(5, start_x, start_y, end_x, end_y)
    
    # 获取标记所有瓦片
    # 将获得的瓦片组合
    # 保存最终图片
    # 删除缓存（若需要）
    # combineTiles(18, (118.05, 24.54), (118.22, 24.41))  # 厦门思明区瓦片组合

if __name__ == '__main__':
    tk = 'd886de1ef37ff05a9f962a235023c76d'
    # get_map(tk, area=(36.79, 115.80, 36.29, 116.39), zoom=12, base_img='vec', over_img='', tile_cache=False, file_name='')
    im = getTile(layer='img', projection='w', zoom='16', x='9689', y='54101', tk='d886de1ef37ff05a9f962a235023c76d')
    im.save('1.png')
    # 不知道为什么，天地图好像失效了，10级以上的底图都显示此区域无底图。最近有洪灾，可能是算力都转移了。
    http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=16&TILEROW=54101&TILECOL=9689&tk=d886de1ef37ff05a9f962a235023c76d